/*-----------------------------------------------------------------------------
	The contents of this file are subject to the Mozilla Public License
	Version 1.1 (the "License"); you may not use this file except in
	compliance with the License. You may obtain a copy of the License at
	http://www.mozilla.org/MPL/
	
	Software distributed under the License is distributed on an "AS IS"
	basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
	License for the specific language governing rights and limitations
	under the License.
	
	The Original Code is Fever Framework code.
	
	The Initial Developer of the Original Code is Romain Ecarnot.
	Portions created by Initial Developer are Copyright (C) 2006
	the Initial Developer. All Rights Reserved.
	
	Contributor(s):
	
	Unless required by applicable law or agreed to in writing, software
	distributed under the License is distributed on an "AS IS" BASIS,
	WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
	See the License for the specific language governing permissions and
	limitations under the License.
-----------------------------------------------------------------------------*/

import org.aswing.border.EmptyBorder;
import org.aswing.BorderLayout;
import org.aswing.CenterLayout;
import org.aswing.Component;
import org.aswing.Container;
import org.aswing.dnd.DragManager;
import org.aswing.dnd.RejectedMotion;
import org.aswing.dnd.SourceData;
import org.aswing.geom.Point;
import org.aswing.GridLayout;
import org.aswing.Insets;
import org.aswing.JButton;
import org.aswing.JFrame;
import org.aswing.JListTree;
import org.aswing.JMenuBar;
import org.aswing.JMenuItem;
import org.aswing.JPanel;
import org.aswing.JScrollPane;
import org.aswing.JSeparator;
import org.aswing.plaf.basic.icon.FrameCloseIcon;
import org.aswing.plaf.basic.icon.FrameNormalIcon;
import org.aswing.tree.TreePath;

import com.bourre.commands.CommandManagerMS;
import com.bourre.commands.Delegate;
import com.bourre.core.HashCodeFactory;
import com.bourre.data.libs.ConfigLoader;
import com.bourre.data.libs.ConfigLoaderEvent;
import com.bourre.data.libs.XMLToObjectDeserializer;
import com.bourre.events.BasicEvent;
import com.bourre.events.BooleanEvent;
import com.bourre.events.BubbleEventBroadcaster;
import com.bourre.events.IEvent;
import com.bourre.transitions.FPSBeacon;
import com.bourre.transitions.IFrameListener;

import fever.app.accelerator.Keyboard;
import fever.app.accelerator.KeyCombo;
import fever.app.accelerator.KeyDefinition;
import fever.app.accelerator.ShortcutLocator;
import fever.app.accelerator.ShortcutMap;
import fever.app.local.Localisation;
import fever.app.local.LocalisationEvent;
import fever.app.local.LocalisationListener;
import fever.data.file.FileFilter;
import fever.events.FeverController;
import fever.events.FeverEventList;
import fever.exception.IllegalAccessException;
import fever.utils.Stringifier;

import fvaswing.components.filechooser.events.FvFileChooserEvent;
import fvaswing.components.FvFileChooser;
import fvaswing.components.FvLabelButton;
import fvaswing.components.menu.FvMenu;
import fvaswing.components.menu.FvMenuItem;
import fvaswing.components.reader.abstract.FvPlayList;
import fvaswing.components.reader.abstract.FvReaderDocument;
import fvaswing.components.reader.abstract.FvReaderEvent;
import fvaswing.components.reader.FvReaderResources;
import fvaswing.components.reader.loader.FvReaderItemBarLoader;
import fvaswing.components.reader.loader.FvReaderItemLoader;
import fvaswing.components.reader.playlist.FvPlayListItem;
import fvaswing.components.reader.playlist.FvPlayListNode;
import fvaswing.components.reader.video.icons.FvResizeIcon;
import fvaswing.FvAsWing;

/**
 * Abstract implementation for "PlayList reader" component.
 * 
 * <p>Load / save playlist operation used argument {@code name} in constructor call to 
 * send / retreive data.
 * 
 * @see fvaswing.components.reader.FvVideoPlayer
 * @see fvaswing.components.reader.FvPaperReader
 * 
 * @author Romain Ecarnot
 */
class fvaswing.components.reader.abstract.FvReader extends BubbleEventBroadcaster 
	implements LocalisationListener, IFrameListener
{
	//-------------------------------------------------------------------------
	// Private properties
	//-------------------------------------------------------------------------
	
	private var _frame : JFrame;
	private var _mainContainer : Container;
	private var _documentContainer : JPanel;
	private var _target : MovieClip;
	
	private var _loaderView : MovieClip;
	private var _loader : FvReaderItemLoader;
	
	private var _document : FvReaderDocument;
	private var _pendingLoad : Boolean;
	private var _pendingItem : FvPlayListItem;
	
	private var _list : FvPlayList;
	
	private var _menubar : JMenuBar;
	private var _fileMenu : FvMenu;
	private var _docMenu : FvMenu;
	private var _openFileItem : FvMenuItem;	private var _openListItem : FvMenuItem;
	private var _showListItem : FvMenuItem;	private var _saveListItem : FvMenuItem;
	private var _clearListItem : JMenuItem;
	private var _closeItem : FvMenuItem;
	
	private var _panelList : JPanel;
	private var _scrollListContainer : JScrollPane;
	private var _panelListContainer : JPanel;
	private var _panelListButton : JPanel;
	private var _closeList : JButton;
	private var _popupList : JButton;
	
	private var _isPopup : Boolean;	
	
	private var _resource : FvReaderResources;
	private var _enabledExternalFile : Boolean;
	
	private var _fileChooser : FvFileChooser;	private var _listChooser : FvFileChooser;
	private var _defaultLisstWidth : Number;
	private var _name : String;
	
	private var _hiddenForce : Boolean;
	private var _playListLoader : ConfigLoader;
	private var _xmlListFile : String;
	
	private var _button : FvLabelButton;
	private var _command : Delegate;
	private var _currentMousePosition : Point;
	private var _pendingResize : Boolean;
	private var _isMinimized : Boolean;
	private var _storedSize : Number;
	
	private var _keyMap : ShortcutMap;
	private var _keyMapName : String;
	
	
	//-------------------------------------------------------------------------
	// Public Properties
	//-------------------------------------------------------------------------
	
	/** Default and minimum with for list in embded mode. */
	public static var DEFAULT_LIST_WITH : Number = 175;
		
			
	//-------------------------------------------------------------------------
	// Public API
	//-------------------------------------------------------------------------
	
	/**
	 * Opens dialog.
	 * 
	 * @param item ( optional ) item to open at startup.
	 */
	public function open( item : FvPlayListItem ) : Void
	{
		_frame.show();
		_frame.setActive( true );
		
		if( item )
		{
			if( _document ) _document.load( item );
			else
			{
				_pendingLoad = true;
				_pendingItem = item;
			}
		}
	}
	
	/**
	 * Loads a playlist xml file definition.
	 * 
	 * <p>Opens the dialog too.
	 * 
	 * @param xmlList relative path to xml file.
	 */
	public function load( xmlList : String ) : Void
	{
		open();
		_loadPlayList( xmlList );
	}
	
	/**
	 * Closes dialog.
	 */
	public function close() : Void
	{
		_frame.tryToClose();
	}
	
	/**
	 * Hides playlist and menubar controls.
	 * 
	 * <p>Caution : can't be undo !
	 */
	public function hidePlayListAndMenu( enabled : Boolean ) : Void
	{
		_hiddenForce = true;
		
		_menubar.setVisible( false );
		_panelList.setVisible( false );
		_list.setEnabled( false );
	}
	
	/**
	 * Returns current {@link fvaswing.components.reader.abstract.FvReaderDocument} 
	 * instance.
	 * 
	 * <p>Overrides method to keep strong typing with custom document
	 */
	public function getDocumentManager() : FvReaderDocument
	{
		return _document;
	}
	
	/**
	 * Adds passed-in {@link fvaswing.components.reader.playlist.FvPlayListItem} 
	 * to playlist.
	 */
	public function addDocument( item : FvPlayListItem ) : Void
	{
		_list.addDocument( item );
	}
	
	/**
	 * Removes passed-in {@link fvaswing.components.reader.playlist.FvPlayListItem} 
	 * from playlist.
	 */
	public function removeDocument( doc : FvPlayListItem ) : Void
	{
		_list.removeDocument( doc );
	}
	
	/**
	 * Defines loader view strategy.
	 * 
	 * @param strategy {@link fvaswing.components.reader.loader.FvReaderItemLoader} strategy
	 */
	public function setLoaderUI( strategy : FvReaderItemLoader ) : Void
	{
		if( strategy != _loader ) _loader = strategy;
	}
	
	/**
	 * Returns loader {@link fvaswing.components.reader.loader.FvReaderItemLoader}.
	 */
	public function getLoaderUI() : FvReaderItemLoader
	{
		return _loader;	
	}
	
	/**
	 * Returns {@code true} if user can load file or playlist file 
	 * using menubar.
	 */
	public function isExternalFileEnabled() : Boolean
	{
		return 	_enabledExternalFile;
	}
	
	/**
	 * Triggered when Localisation language change.
	 */
	public function onLocalisationUpdate( event : LocalisationEvent ) : Void
	{
		_fileMenu.setText( _resource.fileMenuLabel );
		_docMenu.setText( _resource.docMenuLabel );
		
		_showListItem.setText( _resource.showListLabel );
		_closeItem.setText( _resource.closeLabel );
		
		if( _enabledExternalFile )
		{
			_openFileItem.setText( _resource.openFileLabel );
			_openListItem.setText( _resource.openListLabel );
			_saveListItem.setText( _resource.saveListLabel );			_clearListItem.setText( _resource.clearListLabel );
		}
	}
	
	/**
	 * Returns reader name.
	 * 
	 * <p>Also represent the playlist name ( load / save object name ).
	 */
	public function getName() : String
	{
		return _name;	
	}
	
	/**
	 * Returns string representation.
	 */
	public function toString() : String
	{
		return Stringifier.parse( this );
	}
	
	
	//-------------------------------------------------------------------------
	// Private implementation
	//-------------------------------------------------------------------------
	
	/**
	 * Constructor.
	 */
	private function FvReader( name : String, enabledExternalLoading : Boolean )
	{
		super( this );
		
		_name = name;
		
		_resource = FvReaderResources.getInstance();
		Localisation.addLocalisationListener( this );
		
		_pendingLoad = false;
		
		_enabledExternalFile = ( enabledExternalLoading != undefined )
			? enabledExternalLoading
			: false;
		
		_hiddenForce = false;
		
		_pendingResize = false;
		_isMinimized = false;
		_storedSize = DEFAULT_LIST_WITH;
		
		_command = new Delegate( this, _startAnchorResizer );
		
		_keyMapName = HashCodeFactory.getKey( this ).toString();
		_keyMap = ShortcutLocator.getMap( _keyMapName );
		
		_configure();
	}
	
	private function _configure() : Void
	{
		_loader = new FvReaderItemBarLoader();
		
		_configureBasedFrame();
		
		_list = _getPlayList();
		_list.addEventListener( FvPlayList.onOpenFileEVENT, this, _handleOpenFileFromList );		_list.addEventListener( FvPlayList.onEmbedListEVENT, this, _handleEmbedList );		_list.addEventListener( FvPlayList.onCloseListEVENT, this, _handleCloseListByList );		_list.addEventListener( FvPlayList.onLoadListEVENT, this, _handleOpenList );
		
		if( _enabledExternalFile ) _configureChooser();
		
		_mainContainer = _frame.getContentPane();
		_mainContainer.setLayout( new BorderLayout( 5, 5 ) );
		_mainContainer.setBorder( new EmptyBorder( null, new Insets( 5,5,5,5 ) ) );
		_mainContainer.append ( _createMenubar(), BorderLayout.NORTH );		_mainContainer.append ( _createDocumentPanel(), BorderLayout.CENTER );		_mainContainer.append ( _createListPanel(), BorderLayout.WEST );
	}
	
	/**
	 * Overrides for custom filter or chooser properties
	 */
	private function _configureChooser() : Void
	{
		_fileChooser = new FvFileChooser();
		_fileChooser.setMultiSelectionEnabled( false );
		_fileChooser.setAcceptAllFileFilterUsed( true );
		_fileChooser.setPreviewEnabled( false );
		_fileChooser.setUploadEnabled( false );
		_fileChooser.addEventListener( FvFileChooser.onFileChooserEVENT, this, _onHandleFileChooserResult );
		
		_listChooser = new FvFileChooser();
		_listChooser.setMultiSelectionEnabled( false );
		_listChooser.setAcceptAllFileFilterUsed( false );
		_listChooser.setPreviewEnabled( false );
		_listChooser.setUploadEnabled( false );
		_listChooser.addChoosableFileFilter( FileFilter.getXMLFilter() );
		_listChooser.addEventListener( FvFileChooser.onFileChooserEVENT, this, _onHandleListChooserResult );
	}
	
	private function _configureBasedFrame() : Void
	{
		_frame = new JFrame( FvAsWing.getInstance().getRootMovieClip(), "", false );
		_frame.setResizable( true );
		_frame.setClosable( true );
		_frame.setSize( 500, 300 );
		_frame.setDropTrigger( true );
		_frame.setDefaultCloseOperation( JFrame.DISPOSE_ON_CLOSE );
		_frame.addEventListener( JFrame.ON_WINDOW_CLOSING, _releaseDocument, this );
		_frame.addEventListener( Component.ON_DRAG_DROP, _handleDropItem, this );
		_frame.addEventListener( JFrame.ON_WINDOW_ACTIVATED, Delegate.create( this, _toggleKeyMapping, true ) );
		_frame.addEventListener( JFrame.ON_WINDOW_DEACTIVATED, Delegate.create( this, _toggleKeyMapping, false ) );
	}
	
	private function _toggleKeyMapping( source : JFrame, b : Boolean ) : Void
	{
		if( b ) _keyMap.load();
		else _keyMap.unload();
	}
	
	/**
	 * Creates container for embeded playlist.
	 */
	private function _createListPanel() : Container
	{
		_closeList = new JButton( new FrameCloseIcon() );
		_closeList.addActionListener( _handleCloseListByReader, this );
		
		_popupList = new JButton( new FrameNormalIcon() );
		_popupList.addActionListener( _handlePopUpList, this );
		var popKey : KeyDefinition = new KeyCombo( Keyboard.onKeyCONTROL, Keyboard.onKeyB ); 
		_popupList.setToolTipText( popKey.getName() );
		_addShortcut( _popupList, popKey );
		
		_panelListButton = new JPanel( new GridLayout( 1, 2, 5, 5 ) );
		_panelListButton.append( _closeList );
		_panelListButton.append( _popupList );		
		_panelListContainer = new JPanel( new BorderLayout( 5,5 ) );
		_panelListContainer.append( _list.getView(), BorderLayout.CENTER );
		
		_button = new FvLabelButton( "", new FvResizeIcon() );
		_button.setUseHandCursor( false );
		_button.setPreferredSize( 10, 30 );
		_button.addEventListener( JButton.ON_PRESS, _onAnchorResizerPress, this );
		_button.addEventListener( JButton.ON_CLICKED, _onAnchorRelease, this );
		_button.addEventListener( JButton.ON_RELEASEOUTSIDE, _onAnchorRelease, this );
		
		var p1 : JPanel = new JPanel( new CenterLayout() );
		p1.append( _button );
		
		var p2 : JPanel = new JPanel( new BorderLayout( 5,5 ) );
		p2.append( _panelListButton, BorderLayout.SOUTH );
		p2.append( _panelListContainer, BorderLayout.CENTER );
		
		_panelList = new JPanel( new BorderLayout( 5,5 ) );
		_panelList.setPreferredWidth( DEFAULT_LIST_WITH );
		_panelList.append( p2, BorderLayout.CENTER );		_panelList.append( p1, BorderLayout.EAST );		
		_panelList.setDropTrigger( false );
		_panelList.setVisible( false );
		
		_isPopup = false;
		
		return _panelList;
	}
	
	/**
	 * Creates container for document view.
	 * 
	 * <p>Overrides for custom document type.
	 */
	private function _createDocumentPanel() : JPanel
	{
		throw new IllegalAccessException( "_createDocumentPanel() must be override" );
		return null;
	}
	
	private function _initDocumentManager( docManagerType : FvReaderDocument ) : Void
	{
		_document = docManagerType;
		_document.addEventListener( FvReaderDocument.onNewDocumentEVENT, this, _onDocumentStart );
		_document.addEventListener( FvReaderDocument.onLoadDocumentEVENT, this, _onDocumentLoaded );
		_document.addEventListener( FvReaderDocument.onProgressDocumentEVENT, this, _onDocumentProgress );
		_document.addEventListener( FvReaderDocument.onErrorDocumentEVENT, this, _onDocumentError );
	}
	
	private function _setLoaderVisible( b : Boolean ) : Void
	{
		_loaderView._visible = b;	
	}
	
	/**
	 * Locks / unlocks user interactions.
	 */
	private function _lockInteraction( b : Boolean ) : Void
	{
		FeverController.getInstance().broadcastEvent( 
			new BooleanEvent( FeverEventList.onLockInteractionEVENT, b ) 
		);	
	}
	
	/**
	 * Resizes component.
	 */
	private function _handleResizing() : Void
	{
		getDocumentManager().setSize( _documentContainer.getSize( ) );
		_loader.setSize( _documentContainer.getSize() );
	}
	
	private function _addShortcut( component : Component, shortcut : KeyDefinition ) : Void
	{
		_keyMap.registerCustomType( FvAsWing.AWSHORTCUT, shortcut, component );
	}
	
	
	//-------------------------------------------------------------------------
	// Document managment
	//-------------------------------------------------------------------------
	
	/**
	 * Triggered when document starts loading.
	 */
	private function _onDocumentStart( event : FvReaderEvent ) : Void
	{
		_lockInteraction( true );
		_handleResizing();
		_setLoaderVisible( true );
	}
	
	/**
	 * Triggered when document is loaded.
	 */
	private function _onDocumentLoaded( event : FvReaderEvent ) : Void
	{
		_update( event );
		
		_setLoaderVisible( false );
		_handleResizing();
		
		_docMenu.setEnabled( true );
		
		_lockInteraction( false );
	}
	
	/**
	 * Triggered during document loading progression.
	 */
	private function _onDocumentProgress( event : FvReaderEvent ) : Void
	{
		_frame.setTitle( _resource.loadingLabel + " " + _document.getPercent() + " %" );
		_loader.setProgression( _loaderView, getDocumentManager().getPercent() );
	}
	
	/**
	 * Triggered when document loading error occured.
	 */
	private function _onDocumentError( event : FvReaderEvent ) : Void
	{
		_frame.setTitle( _resource.loadingError );
		_setLoaderVisible( false );
		_docMenu.setEnabled( false );
		
		_lockInteraction( false );
	}
	
	/**
	 * Overrides for custom item type
	 */
	private function _update( event : FvReaderEvent ) : Void
	{
		var item : FvPlayListItem = _document.getDocument();
		
		item.setTitle( item.getTitle() );
		_list.updateDocument( item );
		_frame.setTitle( item.getTitle() );	
	}
	
	/**
	 * Dispose document. 
	 */
	private function _releaseDocument( source : JFrame) : Void
	{
		getDocumentManager().release();
		_list.close();
	}
	
	//-------------------------------------------------------------------------
	// Anchor resizer
	//-------------------------------------------------------------------------
	
	/**
	 * Users press the resizer anchor
	 */
	private function _onAnchorResizerPress() : Void
	{
		_currentMousePosition = _button.getMousePosition();
		
		CommandManagerMS.getInstance().delay( _command, 100 );
	}
	
	/**
	 * Users drag the resizer anchor
	 */
	private function _startAnchorResizer() : Void
	{
		_pendingResize = true;
		FPSBeacon.getInstance().addFrameListener( this );
	}
	
	/**
	 * Triggers at each displayed frame by the player.<br />
	 * Resizes playlist container.
	 */
	public function onEnterFrame() : Void
	{
		var newPos : Point = _button.getMousePosition();
		var diffX : Number = _currentMousePosition.x - newPos.x;
		var currentWidth : Number = _panelList.getWidth();
		var newWidth : Number = currentWidth - diffX;
		
		if( ( newWidth > 10 ) && ( newWidth < _getMaximumWidth() ) )
		{
			_applyNewSize( newWidth );
		}
	}
	
	/**
	 * Returns maximum width available for playlist container<br />
	 * Use frame width / 2.
	 */
	private function _getMaximumWidth() : Number
	{
		var min : Number = _frame.getWidth() /2 ;
		return min;
	}
	
	/**
	 * Users release / click on anchor resizer.
	 */
	private function _onAnchorRelease( source : JButton, clickCount : Number ) : Void
	{
		CommandManagerMS.getInstance().remove( _command );
		_onReleaseOutside();
		
		if( !_pendingResize )
		{
			if( !_isMinimized )	_applyNewSize( 10 );
			else _applyNewSize( _storedSize );
			
			_isMinimized = !_isMinimized;
		}
		else
		{
			_isMinimized = false;
			_storedSize = _panelList.getWidth();
		}
		
		_pendingResize = false;
	}
	
	private function _onReleaseOutside( source : JButton ) : Void
	{
		FPSBeacon.getInstance().removeFrameListener( this );	
	}
	 
	private function _applyNewSize( w : Number ) : Void
	{
		_panelList.setWidth( w );
		_panelList.setPreferredWidth( w );	
		_panelList.getParent().revalidateIfNecessary();
	}
	
	//-------------------------------------------------------------------------
	// File Chooser callbacks
	//-------------------------------------------------------------------------
	
	private function _onHandleFileChooserResult( event : FvFileChooserEvent ) : Void
	{
		if( event.getResult() == FvFileChooser.APPROUVE_OPTION )
		{
			var item : FvPlayListItem = new FvPlayListItem( event.getSelectedFile().getPath() );
			_list.addExternalDocument( item );
			getDocumentManager().load( item );
		}
	}
	
	private function _onHandleListChooserResult( event : FvFileChooserEvent ) : Void
	{
		if( event.getResult() == FvFileChooser.APPROUVE_OPTION )
		{
			_loadPlayList( event.getSelectedFile().getPath() );
		}
	}
	
	//-------------------------------------------------------------------------
	// Playlist managment
	//-------------------------------------------------------------------------
	
	/**
	 * Overrides for custom playlist
	 */
	private function _getPlayList() : FvPlayList
	{
		return new FvPlayList( _name, _enabledExternalFile );
	}
	
	private function _loadPlayList( xmlList ) : Void
	{
		if( xmlList && ( xmlList != _xmlListFile ) )
		{
			_lockInteraction( true );
			XMLToObjectDeserializer.PUSHINARRAY_IDENTICAL_NODE_NAMES = true;
			
			var config : Object = new Object();
			
			_playListLoader = new ConfigLoader( config );
			_playListLoader.setAntiCache( true );
			_playListLoader.setURL( xmlList );
			_playListLoader.addEventListener( ConfigLoader.onLoadInitEVENT, this, _onPlayListLoaded, xmlList );
			_playListLoader.load();
		}
	}
	
	private function _onPlayListLoaded( event : ConfigLoaderEvent, xmlList : String ) : Void
	{
		_playListLoader.release();
		_parseNewPlayList( event.getConfig(), xmlList );
	}
	
	private function _parseNewPlayList( o : Object, url : String ) : Void
	{
		throw new IllegalAccessException( "._parseNewPlayList() must be override by reader subclass" );
	}
	
	private function _handlePopUpList( source : JButton ) : Void
	{
		if( !_panelList.isVisible() ) return;
		
		_panelListContainer.removeAll();
		_panelList.setVisible( false );
		_showListItem.setEnabled( false );
		
		_isPopup = true;
		_list.open( true );	
	}
		
	private function _handleEmbedList( event : IEvent ) : Void
	{
		_panelListContainer.append( _list.getView() );
		_showListItem.setEnabled( false );
		_panelList.setVisible( true );	
		_isPopup = false;
	}
	
	private function _handleCloseListByList( event : IEvent ) : Void
	{
		_showListItem.setEnabled( true );
	}
	
	private function _handleCloseListByReader( source : JButton ) : Void
	{
		_panelList.setVisible( false );
		_showListItem.setEnabled( true );
	}
	
	
	//-------------------------------------------------------------------------
	// Menubar
	//-------------------------------------------------------------------------
	
	private function _createMenubar() : JMenuBar
	{
		_fileMenu = new FvMenu( _resource.fileMenuLabel );
		
		if( _enabledExternalFile )
		{
			_openFileItem = _fileMenu.addMenuItem( _resource.openFileLabel, _handleOpenItem, this, new KeyCombo( Keyboard.onKeyCONTROL, Keyboard.onKeyO ) );
			_keyMap.registerCustomType( FvAsWing.AWSHORTCUT, _openFileItem.getShortCut(), _openFileItem );
			
			_openListItem = _fileMenu.addMenuItem( _resource.openListLabel, _handleOpenList, this, new KeyCombo( Keyboard.onKeyCONTROL, Keyboard.onKeyL ) );
			_keyMap.registerCustomType( FvAsWing.AWSHORTCUT, _openListItem.getShortCut(), _openListItem );
			
			_fileMenu.append( new JSeparator( JSeparator.HORIZONTAL ) );
		}
		
		_showListItem = _fileMenu.addMenuItem( _resource.showListLabel, _handleShowList, this );
		
		if( _enabledExternalFile )
		{
			_saveListItem = _fileMenu.addMenuItem( _resource.saveListLabel, _handleSaveList, this, new KeyCombo( Keyboard.onKeyCONTROL, Keyboard.onKeyS ) );
			_keyMap.registerCustomType( FvAsWing.AWSHORTCUT, _saveListItem.getShortCut(), _saveListItem );
			
			_clearListItem = _fileMenu.addMenuItem( _resource.clearListLabel, _handleClearList, this  );
			
			_fileMenu.append( new JSeparator( JSeparator.HORIZONTAL ) );
		}
		
		_closeItem = _fileMenu.addMenuItem( _resource.closeLabel, _handleCloseReader, this, new KeyCombo( Keyboard.onKeyCONTROL, Keyboard.onKeyW ) );
		_keyMap.registerCustomType( FvAsWing.AWSHORTCUT, _closeItem.getShortCut(), _closeItem );
		
		_menubar = new JMenuBar();
		_menubar.append( _fileMenu );
		
		if( _getDocumentMenu().getComponentCount() > 0 ) _menubar.append( _docMenu );
		
		return _menubar;
	}
	
	/**
	 * Overrides for custom document type.
	 */
	private function _getDocumentMenu() : FvMenu
	{
		_docMenu = new FvMenu( _resource.docMenuLabel );
		_docMenu.setEnabled( false );
		
		return _docMenu;
	}
	
	private function _handleOpenItem( source : JMenuItem ) : Void
	{
		if( _openFileItem.isEnabled() )
		{
			_fileChooser.showOpenDialog();
		}
	}
	
	private function _handleShowList( source : JMenuItem ) : Void
	{
		if( _hiddenForce ) return;
		
		if( _showListItem.isEnabled() )
		{
			_showListItem.setEnabled( false );
			
			if( _isPopup ) _list.open( true );
			else
			{
				_panelList.setVisible( true );
			}
		}
	}
	
	private function _handleOpenList( source : FvMenuItem ) : Void
	{
		_listChooser.showOpenDialog();
	}
	
	private function _handleSaveList( source : JMenuItem ) : Void
	{
		if( _saveListItem.isEnabled() ) _list.save();
	}
	
	private function _handleClearList( source : JMenuItem ) : Void
	{
		if( _clearListItem.isEnabled() ) _list.clear();
	}
	
	private function _handleCloseReader( source : JMenuItem ) : Void
	{
		_releaseDocument();
		_frame.tryToClose();
	}
	
	
	//-------------------------------------------------------------------------
	// Reader list callback
	//-------------------------------------------------------------------------
	
	private function _handleDropItem( source : Component, dragInitiator : JListTree, sourceData : SourceData, mousePos : Point ) : Void
	{
		if( sourceData.getName() == _list.getListID() )
		{
			var path : TreePath = TreePath( dragInitiator.getSelectedValue() );
			var node : FvPlayListNode = FvPlayListNode( path.getLastPathComponent() );
			
			if( node.isLeaf() )	_document.load( node.getItem() );
		}
		else DragManager.setDropMotion( new RejectedMotion() );
	}
	
	private function _handleOpenFileFromList( event : BasicEvent ) : Void
	{
		_document.load( event.getTarget() );	
	}
	
}